<?php
declare(strict_types=1);

namespace App\Service;

use App\Model\Dao\ChannelInfoLogDao;
use App\Model\Enum\ChannelInfoTypeEnum;
use App\Model\Enum\PayTypeEnum;
use App\Utils\CustomUtils;
use App\Utils\StringUtils;
use GuzzleHttp\Client;
use Hyperf\Database\Query\Builder;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
use App\Model\Dao\ChannelInfoDao;
use App\Exception\XZXValidationException;
use App\Constants\XZXResponseCode;
use Hyperf\Utils\ApplicationContext;
use Hyperf\Utils\Coroutine;
use App\Utils\DateUtils;
use Hyperf\Utils\Arr;
use Swlib\SaberGM;

class ChannelInfoService {

    /**
     * @Inject()
     * @var ChannelInfoDao
     */
    private $ChannelInfoDao;

    /**
     * @Inject()
     * @var ChannelInfoLogDao
     */
    private $ChannelInfoLogDao;

    /**
     * 列表
     *
     * @param array $param
     *
     * @return array
     */
    public function list (array $param) {

        $limit = $param['limit'];
        $page  = $param['page'];

        $total = $this->ChannelInfoDao->getCount($param);
        $list  = $this->ChannelInfoDao->getList($param, $page, $limit);

        foreach ($list as $k => $v) {
            $v['createTime'] = DateUtils::getDateTime($v['createTime']);
            $v['strStatus']  = $this->ChannelInfoDao->strStatus($v['status']);
            $list[$k]        = $v;
        }

        $data = [
            'total' => $total,
            'list'  => $list,
        ];

        return CustomUtils::xeServiceReturnData(XZXResponseCode::SUCCESS_CODE, XZXResponseCode::getMessage(XZXResponseCode::SUCCESS_CODE), $data);
    }

    /**
     * 详情
     *
     * @param $param
     *
     * @return array
     */
    public function get ($param) {

        $result = $this->ChannelInfoDao->get($param['id']);

        if (!$result) {
            throw new XZXValidationException(XZXResponseCode::getMessage(XZXResponseCode::DATA_NOT_FOUND));
        }

        return CustomUtils::xeServiceReturnData(XZXResponseCode::SUCCESS_CODE, XZXResponseCode::getMessage(XZXResponseCode::SUCCESS_CODE), $result);
    }

    /**
     * 从参数过滤得到添加/更新数组
     *
     * @param $param
     *
     * @return array
     */
    protected function _filterUpdate ($param) {

        $update = Arr::only($param, [
            'status',
            'channelName',
            'bankId',
            'payType',
            'canPay',
            'canTransfer',
            'canRefund',
            'settleCurrency',
            'riskCollectionId',
            // 'channelType',
            'params',
            'remark',
        ]);

        return $update;
    }

    /**
     * 添加
     *
     * @param $param
     *
     * @return array
     * @throws \Throwable
     */
    public function add ($param) {

        $update = $this->_filterUpdate($param);
        $update = array_merge($update, Arr::only($param, ['createBy', 'updateBy']));

        $update['id']        = StringUtils::uuidV4();
        $update['channelNo'] = CustomUtils::createChannelNo();

        $this->ChannelInfoDao->insert($update);

        $data = ['id' => $update['id']];

        $this->_addLog($update['id']);

        return CustomUtils::xeServiceReturnData(XZXResponseCode::SUCCESS_CODE, XZXResponseCode::getMessage(XZXResponseCode::SUCCESS_CODE), $data);
    }

    /**
     * 编辑
     *
     * @param $param
     *
     * @return array
     */
    public function edit ($param) {

        $id = Arr::pull($param, 'id');

        // 检查通道是否存在
        $info = $this->ChannelInfoDao->get($id);
        if (!$info) {
            throw new XZXValidationException(XZXResponseCode::getMessage(XZXResponseCode::DATA_NOT_FOUND));
        }

        $update = $this->_filterUpdate($param);
        $update = array_merge($update, Arr::only($param, ['updateBy']));

        Db::beginTransaction();

        try {

            $this->ChannelInfoDao->update($id, $update);

            $this->_onChannelChange($info['channelNo']);

        } catch (\Throwable $e) {

            Db::rollBack();
            throw $e;
        }
        Db::commit();

        $this->_addLog($id);

        return CustomUtils::xeServiceReturnData(XZXResponseCode::SUCCESS_CODE, XZXResponseCode::getMessage(XZXResponseCode::SUCCESS_CODE), CustomUtils::xzxEmptyObject());
    }

    /**
     * 删除
     *
     * @param $param
     *
     * @return array
     */
    public function del ($param) {

        $id = $param['id'];

        $result = $this->ChannelInfoDao->get($id);

        if (!$result) {
            throw new XZXValidationException(XZXResponseCode::getMessage(XZXResponseCode::DATA_NOT_FOUND));
        }

        // 这里的删除逻辑是将status置为-1
        $update = [
            'status' => -1,
        ];

        Db::beginTransaction();

        try {

            $this->ChannelInfoDao->update($id, $update);
            // $this->ChannelInfoDao->del($param['id'], false);

            $this->_onChannelChange($result['channelNo']);

        } catch (\Throwable $e) {

            Db::rollBack();
            throw $e;
        }

        Db::commit();

        return CustomUtils::xeServiceReturnData(XZXResponseCode::SUCCESS_CODE, XZXResponseCode::getMessage(XZXResponseCode::SUCCESS_CODE), CustomUtils::xzxEmptyObject());
    }

    /**
     * @param $channelNo
     *
     * @throws \Exception
     */
    protected function _onChannelChange ($channelNo) {
        ApplicationContext::getContainer()->get(RiskSyncService::class)->syncChannelCollection([$channelNo]);
    }

    /**
     * 列表-下拉框
     * @param array $param
     *
     * @return array
     */
    public function options (array $param) {

        $list = $this->ChannelInfoDao->getWhereList(function (Builder $query) use ($param) {

            !empty($param['search']) && $query->where('channelName', 'like', "%{$param["search"]}%");
            !empty($param['payType']) && $query->where('payType', $param['payType']);
            !empty($param['canPay']) && $query->where('canPay', $param['canPay']);
            !empty($param['canRefund']) && $query->where('canRefund', $param['canRefund']);
            !empty($param['canTransfer']) && $query->where('canTransfer', $param['canTransfer']);

            $query->where('status', 1);
        });

        $list = array_map(function ($item) {
            return [
                'value'       => $item['id'],
                'label'       => $item['channelName'],
                'id'          => $item['id'],
                'payType'     => $item['payType'],
                'channelName' => $item['channelName'],
                'channelNo'   => $item['channelNo'],
            ];
        }, $list);

        $data = $list;

        return CustomUtils::buildSuccess($data);
    }

    /**
     * 支付方式下拉框
     *
     * @param $param
     */
    public function payTypeOptions ($param) {

        $list = ChannelInfoTypeEnum::born()->getOptions();
        $data = $list;

        return CustomUtils::buildSuccess($data);
    }

    /**
     * 设置通道限额
     *
     * @param $param
     *
     * @return array
     * @throws \Throwable
     */
    public function setTradeLimit ($param) {

        $id = $param['id'];

        $update = Arr::only($param, [
            'amountMin',
            'amountLimit',
            'dayAmountLimit',
            'dayAmountThreshold',
            'dayCountLimit',
            'monthAmountLimit',
            'monthAmountThreshold',
            'monthCountLimit',
        ]);

        $channel = $this->ChannelInfoDao->get($id);

        if (!$channel) {
            throw new \Exception("通道不存在");
        }

        Db::beginTransaction();

        try {

            $this->ChannelInfoDao->set($id, $update);

            $this->_addLog($id);

            $this->_onChannelChange($channel['channelNo']);

        } catch (\Throwable $e) {
            Db::rollBack();
            throw $e;
        }

        Db::commit();

        $data = [];

        return CustomUtils::buildSuccess($data);
    }

    protected function _addLog ($id) {

        $info = $this->ChannelInfoDao->get($id);

        $update              = $info;
        $update['id']        = StringUtils::uuidV4();
        $update['channelId'] = $info['id'];

        unset($update['createTime']);
        unset($update['updateTime']);

        $this->ChannelInfoLogDao->insert($update);
    }

    public function getTradeLimitCost (array $param) {
        $channelNo = $param['channelNo'];
        return ApplicationContext::getContainer()->get(RiskSyncService::class)->getChannelCost($channelNo);
    }

    public function getInfoLog (array $param) {

        $page  = Arr::pull($param, 'page');
        $limit = Arr::pull($param, 'limit');

        $total = $this->ChannelInfoLogDao->getCount($param);
        $list  = $this->ChannelInfoLogDao->getList($param, $page, $limit);

        $list = CustomUtils::formatCreateTime($list);
        foreach ($list as $k => $item) {
            $item['strPayType'] = PayTypeEnum::getLabel($item['payType']);
            $list[$k] = $item;
        }

        $data = [
            'total' => $total,
            'list'  => $list,
        ];

        return CustomUtils::buildSuccess($data);

    }


}
